/**
 *  Copyright (C) 2006 zhangbo (freeeob@gmail.com)
 *
 *  This product is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2.1 of the License, or
 *  (at your option) any later version.
 * 
 *  This product is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 *
 *  author:zhangbo
 *  Email:jsjava@gmail.com
 */

/**  The StatUtils class references to org.apache.commons.math.stat.StatUtils */

function StatUtils(){
	this.jsjava_class="org.apache.commons.math.stat.StatUtils";
}

/**
 * Returns the geometric mean of the entries in the input array, or Double.NaN if the array is empty.
 * @param values
 */
StatUtils.geometricMean=function(values){
	return Math.pow(StatUtils.product(values),1/values.length);
};

/**
 * Returns the maximum of the entries in the input array, or Double.NaN if the array is empty.
 * @param values
 */
StatUtils.max=function(values){
	var max=Double.MIN_VALUE;
	for(var i=0;i<values.length;i++){
		var value=values[i];
		if(value>max){
			max=value;
		}
	}
	return max;
};

/**
 * Returns the arithmetic mean of the entries in the input array, or Double.NaN if the array is empty.
 * @param values
 */
StatUtils.mean=function(values){
	return StatUtils.sum(values)/values.length;
};

/**
 * Returns the mean of the (signed) differences between corresponding elements of the input arrays -- i.e., 
 * sum(sample1[i] - sample2[i]) / sample1.length.
 * @param sample1
 * @param sample2
 */
StatUtils.meanDifference=function(sample1,sample2){
	var length1=sample1.length;
	var length2=sample2.length;
	if(!length1||!length2||length1!=length2){
		return new IllegalArgumentException ("Input arrays must have the same (positive) length.");
	}
	var sample=new Array(length1);
	for(var i=0;i<length1;i++){
		sample[i]=sample1[i]-sample2[i];
	}
	return StatUtils.mean(sample);
};

/**
 * Returns the minimum of the entries in the input array, or Double.NaN if the array is empty.
 * @param values
 */
StatUtils.min=function(values){
	var min=Double.MAX_VALUE;
	for(var i=0;i<values.length;i++){
		var value=values[i];
		if(value<min){
			min=value;
		}
	}
	return min;
};

/**
 * Returns an estimate of the pth percentile of the values in the values array.
 * @param values
 * p
 */
StatUtils.percentile=function(values,p){
	if ((p > 100) || (p <= 0)) {
        throw new IllegalArgumentException("invalid quantile value: " + p);
    }
    var length=values.length;
    if (length == 0) {
        return Double.NaN;
    }
    if (length == 1) {
        return values[0]; 
    }
    var n =  length;
    var pos = p * (n + 1) / 100;
    var fpos = Math.floor(pos);
    var intPos =  fpos;
    var dif = pos - fpos;
    var sorted = new Array(length);
    for(var i=0;i<length;i++){
    	sorted[i]=values[i];
    }
    sorted.sort();
    if (pos < 1) {
        return sorted[0];
    }
    if (pos >= n) {
        return sorted[length - 1];
    }
    var lower = sorted[intPos - 1];
    var upper = sorted[intPos];
    return lower + dif * (upper - lower);
};

/**
 * Returns the product of the entries in the input array, or Double.NaN if the array is empty.
 * @param values
 */
StatUtils.product=function(values){
	var value=1;
	for(var i=0;i<values.length;i++){
		value*=values[i];
	}
	return value;
};

/**
 * Returns the sum of the values in the input array, or Double.NaN if the array is empty.
 * @param values
 */
StatUtils.sum=function(values){
	var sum=0;
	for(var i=0;i<values.length;i++){
		sum+=values[i];
	}
	return sum;
};

/**
 * Returns the sum of the (signed) differences between corresponding 
 * elements of the input arrays -- i.e., sum(sample1[i] - sample2[i]).
 * @param sample1
 * @param sample2
 */
StatUtils.sumDifference=function(sample1,sample2){
	var length1=sample1.length;
	var length2=sample2.length;
	if(!length1||!length2||length1!=length2){
		return new IllegalArgumentException ("Input arrays must have the same (positive) length.");
	}
    var result = 0;
    for (var i = 0; i < length1; i++) {
        result += sample1[i] - sample2[i];
    }
    return result;
};

/**
 * Returns the sum of the natural logs of the entries in the input array, or Double.NaN if the array is empty.
 * @param values
 */
StatUtils.sumLog=function(values){
	var sumLog=0;
	for(var i=0;i<values.length;i++){
		sumLog+=Math.log(values[i]);
	}
	return sumLog;
};

/**
 * Returns the sum of the squares of the entries in the input array, or Double.NaN if the array is empty.
 * @param values
 */
StatUtils.sumSq=function(values){
	var sumLog=0;
	for(var i=0;i<values.length;i++){
		sumLog+=values[i]*values[i];
	}
	return sumLog;
};

/**
 * Returns the variance of the entries in the input array, or Double.NaN if the array is empty.
 * @param values
 */
StatUtils.variance=function(values){
	var v;
	var length=values.length;
	if(length==1){
		return 0.0;
	}
	var mean=StatUtils.mean(values);
	var accum = 0.0;
    var accum2 = 0.0;
    for (var i = 0; i < length; i++) {
        accum += Math.pow((values[i] - mean), 2.0);
        accum2 += (values[i] - mean);
    }
    v=(accum - (Math.pow(accum2, 2) / (length))) /(length - 1);    
    return v;
};

/**
 * Returns the variance of the (signed) differences between corresponding elements of the input 
 * arrays -- i.e., var(sample1[i] - sample2[i]).
 * @param sample1
 * @param sample2
 * @param meanDifference
 */
StatUtils.varianceDifference=function(sample1,sample2,meanDifference){
	var sum1 = 0;
    var sum2 = 0;
    var diff = 0;
    var length1=sample1.length;
	var length2=sample2.length;
	if(!length1||!length2||length1!=length2){
		return new IllegalArgumentException ("Input arrays must have the same (positive) length.");
	}
    for (var i = 0; i < length1; i++) {
        diff = sample1[i] - sample2[i];
        sum1 += (diff - meanDifference) *(diff - meanDifference);
        sum2 += diff - meanDifference;
    }
    return (sum1 - (sum2 * sum2 / length1)) / (length1 - 1);
};